import React, {PureComponent} from 'react';
import {
  View,
  StyleSheet,
  Text,
  TextInput,
  Image,
  TouchableOpacity,
  Keyboard,
  Modal,
  TouchableWithoutFeedback,
  ActivityIndicator,
  KeyboardAvoidingView,
  ScrollView,
  DeviceEventEmitter,
} from 'react-native';
import I18n from 'react-native-i18n';
import {connect} from 'react-redux';
import BaseComponent from '../base/BaseComponent';
import {
  TextButton,
  LinearButton,
  LinearBoardButton,
} from '../../components/Button';
import {NormalHeader} from '../../components/NavigationHeader';
import {showToast} from '../../components/Toast';
import {userLogout} from '../../redux/action';
import Clipboard from '@react-native-community/clipboard';
import {generalNFT} from '../../api/auction';
import * as ImagePicker from 'react-native-image-picker';
import ModalHandler from '../../components/ModalHandler';
import WalletUtils from '../../utils/wallet/WalletUtils';
import createKeccakHash from 'keccak/js';
import bignumber from 'bignumber.js';
import {LinerBoardTextInput} from '../../components/TextInput';
import * as qiniu from 'qiniu-js';
import path from 'path-browserify';
import RNFS from 'react-native-fs';
const rootPath = RNFS.DocumentDirectoryPath;
import {
  queryUploadToken,
  uploadImageToQiNiu,
  registerNftSource,
} from '../../api/auction/index';
import WalletConnectModal from '../../components/WalletConnectModal';
import {Colors} from '../../styles/common';

const fs = require('fs');

const BASE_URL = 'http://assets.signin.art/';

class createNFT extends BaseComponent {
  constructor(props) {
    super(props);

    this.state = {
      name: '',
      link: '',
      image: {},
      file: {},
      info: '',
      description: '',
      modalVisible: false,
      loading: false,
      password: '',
      gasUsed: 0,
      success: false,
      queryingGas: false,
      showWalletConnect: false,
      tx: undefined,
    };
  }

  createNtf = async ({hash, tokenId}) => {
    try {
      let {name, image, link, description, info} = this.state;

      await generalNFT({
        userToken: this.props.userInfo.token,
        hash,
        tokenId,
        info,
        address: this.props.userInfo.metamaskAddress,
      });

      this.setState({
        success: true,
      });

      setTimeout(() => {
        this.setState(
          {
            modalVisible: false,
          },
          () => {
            this.props.navigation.state.params.refresh();
            this.props.navigation.goBack();
          },
        );
      }, 1000);
    } catch (err) {
      console.log(err);
      this.setState(
        {
          modalVisible: false,
          loading: false,
        },
        () => {
          showToast(err.msg || 'failed');
        },
      );
    }
  };
  showImagePicker = (name) => {
    ImagePicker.launchImageLibrary(
      {
        mediaType: 'photo',
        includeBase64: false,
        maxHeight: 200,
        maxWidth: 200,
      },
      (res) => {
        console.log(res);
        if (!res.errorCode && res.uri) {
          this.setState({
            [name]: {
              path: res.uri,
              name: res.fileName,
              mimetype: res.type,
            },
          });
        }
      },
    );
  };

  _handlerView = () => {
    return (
      <View style={{width: '100%'}}>
        <Text
          style={{
            fontWeight: 'bold',
            marginTop: 20,
            marginBottom: 20,
            color: '#6902F4',
            fontSize: 20,
          }}>
          Confirm your transcation
        </Text>
        <Image
          style={{height: 1, width: '100%', marginBottom: 20}}
          source={require('../../assets/auction/line.png')}></Image>
        <View
          style={{
            flexDirection: 'row',
            justifyContent: 'space-between',
            marginBottom: 10,
          }}>
          <Text style={{color: '#6902F4'}}>Call Function</Text>
          <Text style={{color: '#6902F4'}}>register</Text>
        </View>
        <View
          style={{
            flexDirection: 'row',
            justifyContent: 'space-between',
            marginBottom: 20,
          }}>
          <Text style={{color: '#6902F4'}}>Gas Fee</Text>
          <Text
            style={{
              color: '#6902F4',
            }}>{`${this.state.gasUsed}${this.props.gasSymbol}`}</Text>
        </View>
        <LinerBoardTextInput
          style={{
            width: '100%',
            padding: 0,
            height: 44,
          }}
          secureTextEntry={true}
          onChangeText={(text) => {
            this.setState({
              password: text,
            });
          }}
          placeholder="Your wallet password"></LinerBoardTextInput>
        <View
          style={{
            width: '100%',
            flexDirection: 'row',
            justifyContent: 'flex-end',
            marginBottom: 30,
          }}>
          <LinearBoardButton
            buttonStyle={{
              width: 100,
              height: 30,
              marginRight: 20,
            }}
            onPress={() => {
              this.setState({
                modalVisible: false,
              });
            }}
            text={'Cancel'}></LinearBoardButton>
          <LinearButton
            buttonStyle={{
              width: 100,
              height: 30,
            }}
            onPress={this.handlerRegister}
            text={'Confirm'}></LinearButton>
        </View>
      </View>
    );
  };

  registNFTSource = async ({name, description, link, image, file}) => {
    let resources = [
      {
        uri: image.path,
        name: 'image',
      },
    ];

    if (file.path) {
      resources.push({
        uri: file.path,
        name: 'file',
      });
    }
    return await registerNftSource({name, link, description}, resources)
      .then((res) => {
        return res.data.tokenId;
      })
      .catch((err) => {
        console.log('注册nft资源失败');
        console.log(err);
        return null;
      });
  };

  uploadNFT = async ({name, description, link, image, file}, token) => {
    // let url = await qiniu.getUploadUrl({}, token);
    // return this.uploadFile(image.name, image.path, image.mimetype, token, url);

    let tasks = [
      this.uploadFile(image.name, image.path, null, image.mimetype, token),
    ];

    let obj = {
      name,
      description,
      link,
      image: BASE_URL + image.name,
      file: BASE_URL + image.name,
    };

    if (file.path) {
      tasks.push(
        this.uploadFile(file.name, file.path, null, file.mimetype, token),
      );
      obj.file = BASE_URL + file.name;
    }

    console.log('生成并存储Info对象');
    console.log(obj);

    this.setState({
      info: JSON.stringify(obj),
    });

    let buffer = createKeccakHash('keccak256')
      .update(JSON.stringify(obj))
      .digest();
    let big = new bignumber(buffer.toString('hex'), 16);
    let jsonName = big.toFormat({decimalSeparator: ''});

    tasks.push(
      this.uploadFile(
        jsonName,
        null,
        JSON.stringify(obj),
        'application/json',
        token,
      ),
    );

    return Promise.all(tasks)
      .then((result) => {
        console.log('已上传3个nft文件');
        console.log(result);
        return jsonName;
      })
      .catch((err) => {
        console.log('上传文件失败');
        console.log(err);
        return null;
      });
  };

  //构造上传函数
  uploadFile = async (key, localFile, content, mimetype, token, uploadUrl) => {
    var putExtra = {};
    if (mimetype) {
      putExtra.mimeType = mimetype;
    }

    console.log(key);
    console.log(localFile);
    console.log(mimetype);
    console.log(token);

    return uploadImageToQiNiu({
      file: localFile ? {uri: localFile} : content,
      key,
      token,
      putExtra,
    });

    return new Promise((resolve, reject) => {
      let event = qiniu.upload(
        localFile ? {uri: localFile} : content,
        key,
        token,
        putExtra,
      );
      event.subscribe({
        next(res) {
          console.log(key + '上传进度');
          console.log(res);
        },
        error(err) {
          console.log('上传失败');
          console.log(err);
          reject(err);
        },
        complete(res) {
          console.log('上传完成');
          console.log(res);
          resolve(res);
        },
      });
    });
  };

  onPressBackground = () => {
    if (this.state.loading) {
      return;
    }

    this.setState({
      modalVisible: false,
      loading: false,
    });
  };

  handleShowWalletConnect = async () => {
    let {name, image, file, link, description} = this.state;
    if ([name, image, description].some((item) => item.length == 0)) {
      this._showAlert({content: 'enter all required info.'});
      return;
    }
    //生成交易
    this._showLoading();
    try {
      let tokenId = await this.registNFTSource({...this.state});
      // let tokenId = '7839897';
      this.tokenId = tokenId;
      console.log(this.props.userInfo.metamaskAddress);
      let tx = await WalletUtils.getRegisterNFTTx(
        this.props.signinNFT.address,
        tokenId,
        this.props.userInfo.metamaskAddress,
        this.props.userInfo.metamaskAddress,
      );
      console.log(tx);
      this._hideLoading();
      //跳转
      this.setState({
        showWalletConnect: true,
        tx,
      });
    } catch (err) {
      this._hideLoading();
      this._showAlert({content: err?.msg || err + ''});
    }
  };

  showTxModal = async () => {
    this.handleShowWalletConnect();
    return;

    let {name, image, file, link, description} = this.state;
    if ([name, image, description].some((item) => item.length == 0)) {
      this._showAlert({content: 'enter all required info.'});
      return;
    }

    this.setState({
      queryingGas: true,
    });

    WalletUtils.getRegisterNFTGasPrice()
      .then((res) => {
        this.setState({
          queryingGas: false,
          gasUsed: res,
          modalVisible: true,
        });
      })
      .catch((err) => {
        console.log('获取失败');
      });
  };

  handlerRegister = () => {
    Keyboard.dismiss();
    this.setState(
      {
        loading: true,
      },
      async () => {
        console.log(this.state.password);

        try {
          var privateKey = await WalletUtils.privateKeyOfKeystore(
            this.props.userInfo.keystore,
            this.state.password,
          );
        } catch (err) {
          console.log('错误' + err);
          this.setState(
            {
              modalVisible: false,
              loading: false,
            },
            () => {
              this._showAlert({content: 'invalid password'});
            },
          );
          return;
        }

        //android 调用七牛直传接口一直出错，改为服务器转发
        let tokenId = await this.registNFTSource({...this.state});
        //
        // let tokenData = await queryUploadToken({
        //   userToken: this.props.userInfo.token,
        // });
        // console.log('上传token为：' + tokenData.data);
        // let tokenId = await this.uploadNFT({...this.state}, tokenData.data);
        // this.createNtf({hash: res.hashId, tokenId});

        console.log('查看上传文件结果');
        console.log(tokenId);

        if (!tokenId) {
          this.setState(
            {
              modalVisible: false,
              loading: false,
            },
            () => {
              this._showAlert({
                content: 'upload source failed,check your network!',
              });
            },
          );
          return;
        }

        WalletUtils.registerNFT(
          privateKey,
          this.props.signinNFT.address,
          tokenId,
          this.props.userInfo.address,
          (hash) => {
            this.setState({
              result: '交易已发送，正在监听交易->' + hash,
            });
          },
        )
          .then((res) => {
            console.log(res);
            this.createNtf({hash: res.hashId, tokenId});
          })
          .catch((err) => {
            this.setState(
              {
                modalVisible: false,
                loading: false,
              },
              () => {
                this._showAlert({content: 'failed,check your balance'});
              },
            );
          });
      },
    );
  };

  onPressWalletBackground = () => {
    this.setState({
      showWalletConnect: false,
    });
  };

  resultCall = (hash, err) => {
    if (err) {
      this.setState(
        {
          showWalletConnect: false,
        },
        () => {
          this._showAlert({content: err});
        },
      );
      return;
    }
    console.log('收到交易的HASH回调');
    console.log(hash);

    this.setState({
      showWalletConnect: false,
      modalVisible: true,
      loading: true,
    });

    const tokenId = this.tokenId;
    console.log('NFT文件的tokenId为' + tokenId);

    WalletUtils.listenTx(hash)
      .then((res) => {
        console.log('交易已上链' + res);
        this.createNtf({hash, tokenId});
      })
      .catch((err) => {
        console.log('交易失败');
        this.setState(
          {
            modalVisible: false,
            loading: false,
          },
          () => {
            this._showAlert({content: err?.message || err});
          },
        );
      });
  };

  renderComponent = () => {
    let {
      modalVisible,
      image,
      loading,
      success,
      file,
      gasUsed,
      queryingGas,
      showWalletConnect,
      tx,
    } = this.state;
    return (
      <View style={{flex: 1, backgroundColor: '#160231'}}>
        <NormalHeader
          navigation={this.props.navigation}
          text="Create NFT"
          left={{
            icon: require('../../assets/common/common_back_white.png'),
            onPress: () => {
              Keyboard.dismiss();
              this.props.navigation.goBack();
            },
          }}
        />
        <KeyboardAvoidingView
          behavior={Platform.OS == 'ios' ? 'padding' : 'height'}
          style={{flex: 1}}>
          <ScrollView
            keyboardShouldPersistTaps="handled"
            style={{
              flex: 1,
              paddingLeft: 20,
              paddingRight: 20,
            }}>
            <Image
              style={{alignSelf: 'center'}}
              source={require('../../assets/user/user_nft.png')}></Image>
            <Text
              style={{
                marginTop: 10,
                color: '#C917ED',
                fontSize: 18,
                fontWeight: 'bold',
                marginBottom: 20,
              }}>
              Name*
            </Text>
            <LinerBoardTextInput
              placeholder={'Item name'}
              onChangeText={(text) => {
                this.setState({
                  name: text,
                });
              }}></LinerBoardTextInput>
            <Text
              style={{
                marginTop: 10,
                color: '#C917ED',
                fontSize: 18,
                fontWeight: 'bold',
                marginBottom: 10,
              }}>
              Image*
            </Text>
            <Text style={{color: 'white', fontWeight: 'bold'}}>
              File types supported: JPG, PNG
            </Text>
            <TouchableOpacity
              style={{
                marginTop: 20,
                width: 84,
                height: 84,
                borderRadius: 17,
                backgroundColor: 'white',
                alignItems: 'center',
                justifyContent: 'center',
                position: 'relative',
              }}
              onPress={() => {
                this.showImagePicker('image');
              }}>
              <Image
                style={{width: 16, height: 16}}
                source={require('../../assets/auction/nft_add.png')}
              />
              {image.path ? (
                <Image
                  style={{
                    position: 'absolute',
                    left: 0,
                    top: 0,
                    right: 0,
                    bottom: 0,
                    borderRadius: 17,
                  }}
                  source={{uri: image.path}}
                />
              ) : null}
            </TouchableOpacity>
            <Text
              style={{
                marginTop: 10,
                color: '#C917ED',
                fontSize: 18,
                fontWeight: 'bold',
                marginBottom: 10,
              }}>
              File
            </Text>
            <Text style={{color: 'white', fontWeight: 'bold'}}>
              Image, Video, Audio, or 3D Model,File types supported: JPG, PNG,
              GIF, SVG, MP4, WEBM, MP3, WAV, OGG, GLB, GLTF. Max size: 40 MB
            </Text>
            <TouchableOpacity
              style={{
                marginTop: 20,
                width: 84,
                height: 84,
                borderRadius: 17,
                backgroundColor: 'white',
                alignItems: 'center',
                justifyContent: 'center',
                position: 'relative',
              }}
              onPress={() => {
                this.showImagePicker('file');
              }}>
              <Image
                style={{width: 16, height: 16}}
                source={require('../../assets/auction/nft_add.png')}
              />
              {file.path ? (
                <Image
                  style={{
                    position: 'absolute',
                    left: 0,
                    top: 0,
                    right: 0,
                    bottom: 0,
                    borderRadius: 17,
                  }}
                  source={{uri: file.path}}
                />
              ) : null}
            </TouchableOpacity>
            <Text
              style={{
                marginTop: 20,
                color: '#C917ED',
                fontSize: 18,
                fontWeight: 'bold',
                marginBottom: 10,
              }}>
              External Link
            </Text>
            <Text
              style={{color: 'white', fontWeight: 'bold', marginBottom: 20}}>
              Your are welcom to link to your own webpage with more details.
            </Text>
            <LinerBoardTextInput
              placeholder={'URL'}
              style={{with: '100%', height: 40}}
              onChangeText={(text) => {
                this.setState({
                  link: text,
                });
              }}></LinerBoardTextInput>
            <Text
              style={{
                marginTop: 20,
                color: '#C917ED',
                fontSize: 18,
                fontWeight: 'bold',
                marginBottom: 10,
              }}>
              Description*
            </Text>
            <Text
              style={{color: 'white', fontWeight: 'bold', marginBottom: 20}}>
              The Desciption will be included on the item’s detail page
              underneath its image.
            </Text>
            <LinerBoardTextInput
              linearStyle={{height: 120}}
              textInputStyle={{
                textAlignVertical: 'top',
                flex: 1,
              }}
              onChangeText={(text) => {
                this.setState({
                  description: text,
                });
              }}
              placeholder={'input item description'}
              multiline={true}></LinerBoardTextInput>
            <LinearButton
              loading={queryingGas}
              onPress={this.showTxModal}
              text="Create"></LinearButton>
            <View style={{height: 50, width: '100%'}}></View>
            <View
              style={{
                width: '100%',
                height: this.props.widgetLayout.show
                  ? this.props.widgetLayout.height
                  : 0,
                marginTop: 10,
              }}></View>
          </ScrollView>
        </KeyboardAvoidingView>
        <ModalHandler
          visible={modalVisible}
          loading={loading}
          success={success}
          handlerView={this._handlerView}
          onPressBackground={this.onPressBackground}
        />
        <WalletConnectModal
          visible={showWalletConnect}
          resultCall={this.resultCall}
          onPressBackground={this.onPressWalletBackground}
          tx={tx}></WalletConnectModal>
      </View>
    );
  };
}

const mapStateToProps = (state) => ({
  userInfo: state.User.userInfo,
  signinNFT: state.Chain.signinNFT,
  gasSymbol: state.Chain.gasSymbol,
  swapSymbol: state.Chain.swapSymbol,
  widgetLayout: state.Layout.widgetLayout,
});

const mapDispatchToProps = (dispatch) => ({
  userLogout: (item) => dispatch(userLogout()),
});

export default connect(mapStateToProps, mapDispatchToProps)(createNFT);
